#include "Bitmap.h"
#include "Stream.h"

#include "zlib.h"
#include "LightAbstractRenderer.h"
#include "TagList.h"

namespace LightPlayer{

	Bitmap::Bitmap(){
		// init pointer in constructor because init test the "NULLness" of the pointer to delete the buffer and avoid leak
		m_Buffer_RGBA = NULL;
		init();
	}

	Bitmap::~Bitmap(){
		init();
	}

	void Bitmap::init(){
		m_CharacterId = 0;
		m_Width = 0;
		m_Height = 0;
		m_RendererTextureKey = 0;
		// avoid leak if we call init several times
		if(m_Buffer_RGBA){
			delete[] m_Buffer_RGBA;
		}
		m_Buffer_RGBA = NULL;
	}

	void Bitmap::readFromStream( Stream* stream, const TAG& actual_tag, LightAbstractRenderer* pRenderer/* = NULL*/ ){
		init();

		uint8 bitmap_format = stream->read_u8();
		m_Width = stream->read_u16();
		m_Height = stream->read_u16();

		m_Buffer_RGBA = new uint8[ m_Width * m_Height * 4 ]; // alloc RGBA buffer

		if( bitmap_format == 3){
			FillFromIndexColor(stream,actual_tag);
		}
		else if( bitmap_format == 4){
			FillFrom15RGB(stream,actual_tag);
		}
		else if( bitmap_format == 5){
			FillFrom24RGB(stream,actual_tag);
		}

		if(pRenderer){
			m_RendererTextureKey = pRenderer->createTextureFromRowData( m_Buffer_RGBA, m_Width, m_Height );
		}
	}

	void Bitmap::FillFromIndexColor( Stream* stream, const TAG& actual_tag ){
		uint16 BitmapColorTableSize = stream->read_u8() + 1;
		const int byteReaded = 8;
		int size_of_compressed_buffer = actual_tag.size - byteReaded;
		// uncompress zip buffer
		uint8* uncompressed_buffer = new uint8[ m_Width * m_Height * 4 ]; // alloc buffer to read zip buffer
		unsigned long size_of_uncompressed_buffer = m_Width * m_Height * 4;
		int error_code = uncompress(uncompressed_buffer, &size_of_uncompressed_buffer, 
									stream->getCurrentPosition(), size_of_compressed_buffer );
		// skip zip buffer inside real stream
		stream->skip_byte(size_of_compressed_buffer);
		if( error_code == Z_OK ){
			// create temp stream for uncrompressed buffer 
			Stream uncompress_stream( uncompressed_buffer, size_of_uncompressed_buffer );
			// parse uncompress buffer here
			array<RGBA> color_list;
			color_list.resize( BitmapColorTableSize );
			for (uint i=0; i<BitmapColorTableSize; i++){
				if(actual_tag.type != eDefineBitsLossLess2){
					color_list[i].readRGBFromStream( &uncompress_stream );
				}
				else{
					color_list[i].readFromStream( &uncompress_stream );
				}
			}

			int skipped_byte_by_row = 4 - (m_Width % 4);
			if(skipped_byte_by_row >= 4){ skipped_byte_by_row = 0; }

			int index = 0;
			for (int j=0; j<m_Height; j++){
				for (int i=0; i<m_Width; i++){
					uint8 color_index = uncompress_stream.read_u8();

					m_Buffer_RGBA[index + 0] = color_list[color_index].R;
					m_Buffer_RGBA[index + 1] = color_list[color_index].G;
					m_Buffer_RGBA[index + 2] = color_list[color_index].B;
					if(actual_tag.type != eDefineBitsLossLess2){
						m_Buffer_RGBA[index + 3] = 255;
					}
					else{
						m_Buffer_RGBA[index + 3] = color_list[color_index].A;
					}

					index += 4;
				}
				uncompress_stream.skip_byte(skipped_byte_by_row);
			}
			assert( index == (m_Height*m_Width*4) );
		}

		// delte temp uncompressed buffer
		delete[] uncompressed_buffer;
	}

	void Bitmap::FillFrom15RGB( Stream* stream, const TAG& actual_tag ){
		const int byteReaded = 7;
		int size_of_compressed_buffer = actual_tag.size - byteReaded;
		// uncompress zip buffer
		uint8* uncompressed_buffer = new uint8[ m_Width * m_Height * 4 ]; // alloc buffer to read zip buffer
		unsigned long size_of_uncompressed_buffer = m_Width * m_Height * 4;
		int error_code = uncompress(uncompressed_buffer, &size_of_uncompressed_buffer, 
			stream->getCurrentPosition(), size_of_compressed_buffer );
		// skip zip buffer inside real stream
		stream->skip_byte(size_of_compressed_buffer);
		if( error_code == Z_OK ){
			// create temp stream for uncompressed buffer 
			Stream uncompress_stream( uncompressed_buffer, size_of_uncompressed_buffer );
			// parse uncompress buffer here
			int skipped_byte_by_row = (m_Width % 2) == 0 ? 0 : 1;
			int index = 0;
			for (int j=0; j<m_Height; j++){
				for (int i=0; i<m_Width; i++){

					uncompress_stream.read_bool(); // skip bit
					uint8 color_r = uncompress_stream.read_uint(5);
					uint8 color_g = uncompress_stream.read_uint(5);
					uint8 color_b = uncompress_stream.read_uint(5);

					m_Buffer_RGBA[index + 0] = color_r;
					m_Buffer_RGBA[index + 1] = color_g;
					m_Buffer_RGBA[index + 2] = color_b;
					m_Buffer_RGBA[index + 3] = 255;

					index += 4;
				}
				uncompress_stream.skip_byte(skipped_byte_by_row);
			}
			assert( index == (m_Height*m_Width*4) );
		}

		// delete temp uncompressed buffer
		delete[] uncompressed_buffer;
	}

	void Bitmap::FillFrom24RGB( Stream* stream, const TAG& actual_tag ){
		const int byteReaded = 7;
		int size_of_compressed_buffer = actual_tag.size - byteReaded;
		// uncompress zip buffer
		uint8* uncompressed_buffer = new uint8[ m_Width * m_Height * 4 ]; // alloc buffer to read zip buffer
		unsigned long size_of_uncompressed_buffer = m_Width * m_Height * 4;
		int error_code = uncompress(uncompressed_buffer, &size_of_uncompressed_buffer, 
			stream->getCurrentPosition(), size_of_compressed_buffer );
		// skip zip buffer inside real stream
		stream->skip_byte(size_of_compressed_buffer);
		if( error_code == Z_OK ){
			// create temp stream for uncrompressed buffer 
			Stream uncompress_stream( uncompressed_buffer, size_of_uncompressed_buffer );
			// parse uncompress buffer here
			int index = 0;
			for (int j=0; j<m_Height; j++){
				for (int i=0; i<m_Width; i++){

					uint8 color_a = uncompress_stream.read_u8();
					uint8 color_r = uncompress_stream.read_u8();
					uint8 color_g = uncompress_stream.read_u8();
					uint8 color_b = uncompress_stream.read_u8();

					m_Buffer_RGBA[index + 0] = color_r;
					m_Buffer_RGBA[index + 1] = color_g;
					m_Buffer_RGBA[index + 2] = color_b;
					if(actual_tag.type != eDefineBitsLossLess2){
						m_Buffer_RGBA[index + 3] = 255;
					}
					else{
						m_Buffer_RGBA[index + 3] = color_a;
					}

					index += 4;
				}
			}
			assert( index == (m_Height*m_Width*4) );
		}

		// delte temp uncompressed buffer
		delete[] uncompressed_buffer;
	}

};